package zcatt.examples.swt.widgets;

import static org.eclipse.swt.events.SelectionListener.widgetSelectedAdapter;

import java.time.Instant;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Caret;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.IME;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;

public class CanvasTab extends WidgetTab {
	final static int GRAB_RADIUS = 5;
	
	final static int STATE_NORMAL = 0;
	final static int STATE_ONGRAB = 1;
	final static int STATE_DRAGGING =2;
	
	final static int LEFTTOP = 1;
	final static int TOP = 2;
	final static int RIGHTTOP = 3;
	final static int LEFT = 4;
	final static int CENTER = 5;
	final static int RIGHT = 6;
	final static int LEFTBOTTOM = 7;
	final static int BOTTOM = 8;
	final static int RIGHTBOTTOM = 9;
	
	int state;
	int grab;	
	Point[] ptGrabs;

	
	Point ptCircle;
	int radius;
	int minR;
	int maxR;
	Rectangle clientRect;
	String inputText;
	Point ptText;

	Canvas canvas;	
	Button btnDoubleBuffer;
	Button btnShowCaret;
	IME ime;
	
	public CanvasTab(WidgetExample example) {
		super(example);
		radius = -1;		
		state = STATE_NORMAL;
		grab = 0;
		btnDoubleBuffer = null;
	}

	@Override
	public void dispose() {
	}
	
	void initial(Rectangle rect)
	{
		if (radius > 0 )
			return;
		
		clientRect = rect;
		minR = GRAB_RADIUS *3;
		maxR = Math.min(rect.height,  rect.width) /2 -1;
		radius = Math.min(rect.height,  rect.width) /4;
		ptCircle = new Point(rect.width/2, rect.height/2);		

		setGrabPoints();
	}	
	
	void setGrabPoints()
	{
		ptGrabs= new Point[] {	//按照grab排列
				new Point(ptCircle.x -radius, ptCircle.y -radius),
				new Point(ptCircle.x, ptCircle.y -radius),
				new Point(ptCircle.x +radius, ptCircle.y -radius),
				new Point(ptCircle.x -radius, ptCircle.y),
				new Point(ptCircle.x, ptCircle.y),
				new Point(ptCircle.x +radius, ptCircle.y),
				new Point(ptCircle.x -radius, ptCircle.y +radius),
				new Point(ptCircle.x, ptCircle.y +radius),
				new Point(ptCircle.x +radius, ptCircle.y +radius),
		};		
	}
	
	boolean isDragging()
	{
		return state == STATE_DRAGGING; 
	}

	boolean isOnGrab()
	{
		return state == STATE_ONGRAB; 
	}
	
	boolean setState(int state, int grab)
	{
		boolean done = false;
		if(this.state == state)
		{
			if((isDragging() || isOnGrab()) && this.grab != grab)
			{
				this.grab = grab;
				setCursor();
				done = true;
			}
		}
		else
		{
			this.state = state;
			this.grab = grab;			
			setCursor();
			done = true;
		}
		return done;
	}
	
	void setCursor()
	{
		if(state == STATE_NORMAL)
		{
			canvas.setCursor(null);
		}
		else 
		{
			int cursorStyle = SWT.CURSOR_SIZEALL;
			
			if(grab == TOP || grab == BOTTOM)
			{
				cursorStyle = SWT.CURSOR_SIZENS;
			}
			else if(grab == LEFT || grab == RIGHT)
			{
				cursorStyle = SWT.CURSOR_SIZEWE;				
			}
			else if(grab == LEFTTOP || grab == RIGHTBOTTOM)
			{
				cursorStyle = SWT.CURSOR_SIZENWSE;				
			}
			else if(grab == RIGHTTOP || grab == RIGHTTOP)
			{
				cursorStyle = SWT.CURSOR_SIZENESW;				
			}
			canvas.setCursor(canvas.getDisplay().getSystemCursor(cursorStyle));
		}			
	}
	
	//return 0 if not on grab
	int getGrab(int x, int y)
	{
		Rectangle rect = new Rectangle(x - GRAB_RADIUS, y - GRAB_RADIUS, GRAB_RADIUS*2, GRAB_RADIUS*2);
		for(int i = 0; i < ptGrabs.length; i++)
		{
			if(rect.contains(ptGrabs[i]))
				return i+1;
		}
		
		return 0;
	}
	
	boolean dragMove(int x, int y)
	{
		boolean done = false;
		int r = radius;
		Point pt = new Point(ptCircle.x, ptCircle.y);

		if(grab == TOP)
		{
			r = pt.y - y;
		}
		else if(grab == BOTTOM)
		{
			r = y - pt.y;			
		}
		else if(grab == LEFT)
		{
			r = pt.x - x;
			
		}
		else if(grab == RIGHT)
		{
			r = x - pt.x;
		}
		else if(grab == LEFTTOP)
		{
			r = Math.min(pt.x -x , pt.y -y);
		}
		else if(grab == RIGHTBOTTOM)
		{
			r = Math.min(x - pt.x , y - pt.y);			
		}
		else if(grab == LEFTBOTTOM)
		{
			r = Math.min(pt.x - x, y - pt.y);
		}
		else if(grab == RIGHTTOP)
		{
			r = Math.min(pt.x - x, pt.y - y);			
		}
		else 
		{
			assert grab == CENTER;
			pt.x = x;
			pt.y = y;			
		}

		if(	(r != radius || !pt.equals(ptCircle)) 
				&& r> minR
				&& pt.x - r >= clientRect.x
				&& pt.x + r < clientRect.x + clientRect.width
				&& pt.y -r >= clientRect.y
				&& pt.y +r < clientRect.y + clientRect.height
			)
		{
			ptCircle = pt;
			radius = r;			
			setGrabPoints();
			canvas.redraw();
			done = true;
		}
		
		return done;
	}
	

	@Override
	public String getText() {
		return "Canvas";
	}

	@Override
	public String getCategory() {
		return "Misc";
	}

	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return "Show canvas.";
	}

	@Override
	public void createWidget(Composite parent) {
		canvas = new Canvas(parent, btnDoubleBuffer.getSelection()? SWT.DOUBLE_BUFFERED :SWT.NONE);
		canvas.addDisposeListener(event->{
			//TODO
		});
		
		canvas.addPaintListener(event -> {
			//System.out.println(Instant.now());
			Rectangle rect = canvas.getClientArea();

			initial(rect);
			
			GC gc = event.gc;
			gc.drawLine(0, 0, rect.width -1, rect.height -1);
			gc.drawLine(rect.width -1, 0, 0, rect.height -1);
			
			gc.drawOval(ptCircle.x - radius, ptCircle.y - radius, radius*2, radius*2);
			
			
			gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GREEN));
			for(int i = 0; i< ptGrabs.length; i++)
			{	
				Point e = ptGrabs[i];
				
				if(canvas.isFocusControl()) 
				{
					int color = SWT.COLOR_RED;
					if(i+1 == grab) 
					{
						if(isDragging() && i+1 == grab)
						{
							color = SWT.COLOR_GREEN;
						}
						else if(isOnGrab())
						{
							color = SWT.COLOR_BLUE;
						}						
					}
					
					gc.setBackground(gc.getDevice().getSystemColor(color));						
					gc.fillRectangle(e.x - GRAB_RADIUS, e.y-GRAB_RADIUS, GRAB_RADIUS*2, GRAB_RADIUS*2);
				}
				else
				{
					gc.drawRectangle(e.x - GRAB_RADIUS, e.y-GRAB_RADIUS, GRAB_RADIUS*2, GRAB_RADIUS*2);					
				}				
			}
			
			Caret caret = canvas.getCaret();
			if(caret != null)
			{
				ptText = caret.getLocation();
			}
			if(inputText != null)
			{
				gc.drawString(inputText, ptText.x, ptText.y, true);
			}
		});

		//添加keyListener以允许canvas获得focus. see Composite.hooksKeys().
		canvas.addKeyListener(new KeyAdapter() {});
/*		
		canvas.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				//e.doit = true;
			}
			@Override
			public void keyReleased(KeyEvent e) {
				//e.doit = true;
			}
		});
*/
		
		canvas.addFocusListener(new FocusListener() {

			@Override
			public void focusGained(FocusEvent e) {
				canvas.redraw();
			}

			@Override
			public void focusLost(FocusEvent e) {
				canvas.redraw();				
			}
			
		});
		
		canvas.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseDown(MouseEvent e) {
				int curGrab = getGrab(e.x, e.y);
				if(curGrab != 0)
				{
					setState(STATE_DRAGGING, curGrab);
					canvas.setCapture(true);
				}				
			}

			@Override
			public void mouseUp(MouseEvent e) {
				if(isDragging())
				{
					setState(STATE_NORMAL, 0);
					canvas.setCapture(false);
				}
			}			
		});
		
		canvas.addMouseMoveListener(new MouseMoveListener() {

			@Override
			public void mouseMove(MouseEvent e) {
				boolean done = false;
				if(!isDragging())
				{
					int curGrab = getGrab(e.x, e.y);
					done = setState((curGrab == 0)? STATE_NORMAL : STATE_ONGRAB, curGrab);
				}
				else
				{
					done = dragMove(e.x, e.y);					
				}
				
				if(done)
					canvas.redraw();				
			}			
		});

	}
	
	@Override
	public void createControlPanel(Composite parent)
	{
		Composite comp = new Composite(parent, SWT.NONE);
		GridLayout gridLayout;
		gridLayout = new GridLayout(3, true);
		comp.setLayout(gridLayout);
		
		Group grp;
		
		grp = new Group(comp, SWT.NONE);
		grp.setText("options");;
		gridLayout = new GridLayout();
		grp.setLayout(gridLayout);
		
		Button btn;
		
		btnShowCaret = new Button(grp, SWT.CHECK);
		btnShowCaret.setText("Show caret");
		btnShowCaret.addSelectionListener(widgetSelectedAdapter(event -> {
			//Button btnShowCaret = (Button) event.widget;
			ime = canvas.getIME();
			if(ime != null) {
				ime.dispose();
			}

			if(btnShowCaret.getSelection())
			{
				Caret caret = new Caret(canvas, SWT.NONE);
				
				Font font = canvas.getFont();
				GC gc = new GC(canvas);
				gc.setFont(font);
				caret.setBounds(10,10,1,gc.getFontMetrics().getHeight());
				gc.dispose();
				
				canvas.setCaret(caret);
				canvas.setFocus();

				//仅粗略展示IME的使用
				ime = new IME(canvas, SWT.NONE);
				ime.addListener(SWT.ImeComposition, imeEvent -> {
					switch (imeEvent.detail) {
					case SWT.COMPOSITION_SELECTION: //that indicates that IME needs the selected text and its startand end offsets (value is 3).
						//handleCompositionSelection(event); 
						System.out.println("comp selection");
						imeEvent.index = 0;
						imeEvent.count = 0;
						break;
					case SWT.COMPOSITION_CHANGED: //indicates a change in the IME composition.
						//handleCompositionChanged(event);
						System.out.println("comp changed: "+imeEvent.text);
						inputText = imeEvent.text;
						canvas.redraw();
						break;
					case SWT.COMPOSITION_OFFSET: // indicates that the IME needs the offset for a given location.
						//handleCompositionOffset(event);
						System.out.println("comp offset");
						imeEvent.start = 0;
						imeEvent.end = 0;
						imeEvent.text = "";
						break;
				}
					
				});
			}
			else
			{
				
				canvas.setCaret(null);
			}
		}));
		
		btn = new Button(grp, SWT.CHECK);
		btn.setText("popup menu");
		btn.addSelectionListener(widgetSelectedAdapter(event -> {
			Menu menu = canvas.getMenu();
			if (menu != null) {
				menu.dispose();
			}
			canvas.setMenu(null);

			Button btnContextMenu = (Button) event.widget;
			if(btnContextMenu.getSelection())
			{
				menu = new Menu(canvas.getShell(), SWT.POP_UP);
				MenuItem item = new MenuItem(menu, SWT.PUSH);
				item.setText("canvas popup menu");
				item.addSelectionListener(widgetSelectedAdapter(e -> {
					MessageBox mb = new MessageBox(canvas.getShell(), SWT.YES|SWT.ICON_INFORMATION);
					mb.setText("Popup");
					mb.setMessage("Popup menu is triggered!");
					mb.open();
				}));
				canvas.setMenu(menu);				
			}
		}));
		
		btnDoubleBuffer = new Button(grp, SWT.CHECK);
		btnDoubleBuffer.setText("double buffer");
		btnDoubleBuffer.addSelectionListener(widgetSelectedAdapter(event -> {
			example.recreateWidgetComp();
			canvas.redraw();
			//canvas.update();
		}));

		grp = new Group(comp, SWT.NONE);
		grp.setText("radio");;
		gridLayout = new GridLayout();
		grp.setLayout(gridLayout);

		grp = new Group(comp, SWT.NONE);
		grp.setText("custom");
		gridLayout = new GridLayout();
		grp.setLayout(gridLayout);
		
		
		
	}
	

}
